package cn.bookcycle.panda.pay.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.bookcycle.panda.pay.constant.BusinessData;
import cn.bookcycle.panda.pay.constant.NameData;
import cn.bookcycle.panda.pay.constant.SymbolData;
import cn.bookcycle.panda.pay.constant.WeChatData;

/**
 * 微信工具类，用于生成微信请求需要的一些随机参数
 * 有如下两个工具：
 * generateNonceStr()，生成32位随机字符串
 * Sign()，生成签名
 *
 * @author liufenglin
 * @date 2018年1月31日
 */
public class WechatUtil {
	private static final Logger logger = LoggerFactory.getLogger(WechatUtil.class);
	
	/**AppId，固定*/
	private static String APP_ID_JOINT;
	/**商户ID，固定*/
	private static String MCH_ID_JOINT;
	/**回调地址，固定*/
	private static String NOTIFY_URL_JOINT = BusinessData.NECESSARY_PARAMETERS_MAP.get(NameData.NOTIFY_URL) + SymbolData.EQUAL_SIGN + WeChatData.NOTIFY_URL_VALUE;
	/**交易类型，目前固定*/
	private static String TRADE_TYPE_JOINT = BusinessData.NECESSARY_PARAMETERS_MAP.get(NameData.TRADE_TYPE) + SymbolData.EQUAL_SIGN + WeChatData.TRADE_TYPE_VALUE;
	/**密钥，固定*/
	private static String KEY_JOINT;
	
	/**
	 * 通过account参数，修改APP_ID、MCH_ID参数
	 * 
	 * @param account
	 */
	public static void initSignPara(String account) {
		APP_ID_JOINT = BusinessData.NECESSARY_PARAMETERS_MAP.get(NameData.APP_ID) + SymbolData.EQUAL_SIGN + BusinessData.APP_ID_MAP.get(account).toString();
		MCH_ID_JOINT = BusinessData.NECESSARY_PARAMETERS_MAP.get(NameData.MCH_ID) + SymbolData.EQUAL_SIGN + BusinessData.MCH_ID_MAP.get(account).toString();
		KEY_JOINT = NameData.KEY + SymbolData.EQUAL_SIGN + BusinessData.KEY_MAP.get(account).toString();
	}
	
	/**
	 * 生成不32位的随机字符串
	 * 
	 * @return 长度为32位的随机字符串
	 */
	public static String generateNonceStr() {
		// 创建随机对象，用于调用随机方法
		Random random = new Random();
		// 数字ascii码的基数
		int digitBase = 48;
		// 字母ascii码的基数
		int alphabetBase = 65;
		// 选择生成字母还是数字
		int select = 0;
		// 用于拼凑随机字符串
		StringBuilder stringBuilder = new StringBuilder();
		// 循环生成32位
		for (int i = 0; i < 32; ++i) {
			// 随机选择生成字母或数字
			select = random.nextInt(7);
			// 有3/8的机会生成数字
			if (select <= 2) {
				// 生成数字，数字0-9的ascii码返回是：48~57
				stringBuilder.append((char) (random.nextInt(9) + digitBase));
			} else {
				// 生成字母，有5/8的机会生成字母，大写字母ascii码范围是：65~90
				stringBuilder.append((char) (random.nextInt(25) + alphabetBase));
			}
		}
		return stringBuilder.toString();
	}
	
	
	/**
	 * 根据参数生成签名
	 * 
	 * @param outTradeNoJoint 订单号
	 * @param spbillCreateipJoint 用户设备IP
	 * @param totalFeeJoint 总价，以分为单位
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	private static String Sign(String bodyJoint, String nonceStrJoint, String outTradeNoJoint, String spbillCreateipJoint, String totalFeeJoint) throws UnsupportedEncodingException {
		/*
		 * 参数格式例子：
		 * attach = "attach=payTest"
		 * body = "body=wsnTest"
		 * nonceStr = "nonce_str=5K8264ILTKCH16CQ2502SI8ZNMTM67VW" 由提供函数生成
		 * outTradeNo = "out_trade_no=0002";
		 * spbillCreateip = "spbill_create_ip=123.12.12.123"
		 * totalFee = "total_fee=1"
		 */
		// 对所有参数值不为空的参数名做字典排序
		String sign = null;
		String[] parrName = new String[] { APP_ID_JOINT, bodyJoint, MCH_ID_JOINT, nonceStrJoint, NOTIFY_URL_JOINT, outTradeNoJoint,
				spbillCreateipJoint, totalFeeJoint, TRADE_TYPE_JOINT};
		Arrays.sort(parrName);
		StringBuilder stringBuilder = new StringBuilder();
		for (int i = 0; i < parrName.length; ++i) {
			if (i != parrName.length - 1) {
				stringBuilder.append(parrName[i] + "&");
			} else {
				stringBuilder.append(parrName[i]);
			}
		}
		// 按照字典序拼接好所有的参数为字符串stringAppend
		String stringAppend = stringBuilder.toString();
		// 拼接API密钥
		String stringSignTemp=stringAppend + "&" + KEY_JOINT;
		logger.info("连接商户key后的字符串:{}", stringSignTemp);
		// 进行MD5加密。并转化为大写
		try {
			MessageDigest md5Digest = MessageDigest.getInstance("MD5");
			byte[] encodeMd5Digest = md5Digest.digest(stringSignTemp.getBytes(NameData.UTF8));
			sign = byteToHexString(encodeMd5Digest).toUpperCase();
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		logger.info("MD5加密后得到的sign:{}", sign);
		return sign;
	}
	

	/**
	 * 字节数组转十六进制字符串
	 * 
	 * @param bytes 字节数组
	 * @return 十六进制字符串
	 */
	public static String byteToHexString(byte[] bytes) {
		String result = "";
		for (int i = 0; i < bytes.length; ++i) {
			int temp = bytes[i] & 0xff;
			String tempHex = Integer.toHexString(temp);
			if (tempHex.length() < 2) {
				result += "0" + tempHex;
			} else {
				result += tempHex;
			}
		}
		return result;
	}
	
	
	/**
	 * 给外部调用，用来计算sign
	 * 
	 * @param map
	 * @param nonceStr
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public static String computeSign(Map<String, Object> map, String nonceStr) throws UnsupportedEncodingException {
		logger.info("computeSign 接收到的map参数是：{}", map.toString());
		String body = map.get(BusinessData.NECESSARY_PARAMETERS_MAP.get(NameData.BODY)).toString();
		String outTradeNo = map.get(BusinessData.NECESSARY_PARAMETERS_MAP.get(NameData.TRADE_NO)).toString();
		String spbillCreateip = map.get(BusinessData.NECESSARY_PARAMETERS_MAP.get(NameData.SPBILL_CREATE_IP)).toString();
		String totalFee = map.get(BusinessData.NECESSARY_PARAMETERS_MAP.get(NameData.TOTAL_FEE)).toString();
		
		Map<String, String> encryptMap = new HashMap<String, String>();
		
		// 将微信请求参数名字、和值放入map
		encryptMap.put(BusinessData.NECESSARY_PARAMETERS_MAP.get(NameData.BODY), body);
		// 将含有一个参数的map，转化为key=value的形式
		String bodyJoint = DataFormatConvert.delBrackets(encryptMap.toString());
		// 清空map，提供给下一个参数转化形式使用
		encryptMap.clear();
		
		encryptMap.put(BusinessData.NECESSARY_PARAMETERS_MAP.get(NameData.NONCE_STR), nonceStr);
		String nonceStrJoint = DataFormatConvert.delBrackets(encryptMap.toString());
		encryptMap.clear();
		
		encryptMap.put(BusinessData.NECESSARY_PARAMETERS_MAP.get(NameData.TRADE_NO), outTradeNo);
		String outTradeNoJoint = DataFormatConvert.delBrackets(encryptMap.toString());
		encryptMap.clear();
				
		encryptMap.put(BusinessData.NECESSARY_PARAMETERS_MAP.get(NameData.SPBILL_CREATE_IP), spbillCreateip);
		String spbillCreateipJoint = DataFormatConvert.delBrackets(encryptMap.toString());
		encryptMap.clear();
		
		encryptMap.put(BusinessData.NECESSARY_PARAMETERS_MAP.get(NameData.TOTAL_FEE), totalFee);
		String totalFeeJoint = DataFormatConvert.delBrackets(encryptMap.toString());
		encryptMap.clear();
		return Sign(bodyJoint, nonceStrJoint, outTradeNoJoint, spbillCreateipJoint, totalFeeJoint);
	}
	
//	public static void main(String[] args) {
//		// 生成32位随机字符串
////		System.out.println(generateNonceStr());
//		
//		// 生成签名
//		/*
//		 * 必须填写的参数依次是：
//		 * body = "body=详细字段"
//		 * nonceStr = "nonce_str=G82573W57A8U5KKDJQTNIJT1E5KLECRD" 由提供函数生成，可以定期变换
//		 * outTradeNo = "out_trade_no=2018011055623546757";
//		 * spbillCreateip = "spbill_create_ip=123.12.12.123"
//		 * totalFee = "total_fee=1"
//		 */
//		// 正确的签名是5D6EB468516F6A6D15E0E24C977AF629
//		System.out.println(Sign(
//				"body=商品测试", 
//				"nonce_str=G82573W57A8U5KKDJQTNIJT1E5KLECRD",
//				"out_trade_no=2018011055623546709", 
//				"spbill_create_ip=123.123.123.123", 
//				"total_fee=1"));
//	}
}
